
import 'dart:async';

import 'dart:core';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:logger/logger.dart' show Level;
// import 'package:http/http.dart';

class YKAudioPlayerDelegate {

  void Function(String msg)? msgCallBack;

  void Function()? finishCallBack;

  YKAudioPlayerDelegate({this.msgCallBack, this.finishCallBack});
}

class YKAudioPlayer {

  static YKAudioPlayer? _instance;

  final Map<String, String> _recordMap = Map<String, String>();

  final Map<String, dynamic> _recordDataMap = Map<String,dynamic>();

  static YKAudioPlayer get instance {
    _instance ??= YKAudioPlayer._();
    return _instance!;
  }

  String? _currentPlayingId;

  double _progress = 0.0;

  YKAudioPlayerDelegate? _delegate;

  FlutterSoundPlayer? _player;

  Duration? _currentDuration; 

  StreamController<double> _progressStream = StreamController<double>.broadcast();

  StreamSubscription<PlaybackDisposition>? _disposition;

  String? get currentPlayingId => _currentPlayingId;

  double get progress => _progress;

  Stream<double> get progressStream => _progressStream.stream;

  YKAudioPlayer._() { }

  void regis({required String id, required String url, dynamic data = null}) {
    if (id.isNotEmpty && url.isNotEmpty) {
      _recordMap.addAll({id:url});
    }
    if (id.isNotEmpty && data != null) {
      _recordDataMap.addAll({id:data});
    }
  }

  Future<void> play(String id, {YKAudioPlayerDelegate? delegate, bool endLast = false}) async {

    if (endLast) {
      await end();
    } else {
      if (_currentPlayingId != null) {
        delegate?.msgCallBack?.call("已有音频正在播放");
        return;
      }
    }


    if (_recordMap.keys.contains(id) || _recordDataMap.keys.contains(id)) {
      _delegate = delegate;
      await _play(id);
    } else {
      delegate?.msgCallBack?.call("未找到注册音频");
    }
  }

  Future<void> end() => _finish();

  Future<void> _play(String id) async {

    _player = await FlutterSoundPlayer(logLevel: Level.error).openPlayer();

    await _player?.setSubscriptionDuration(const Duration(milliseconds: 10));
    _disposition = _player?.onProgress?.listen((event) {
      double progress = (event.position.inMicroseconds.toDouble() / event.duration.inMicroseconds.toDouble());
      _progress = progress;
      try {
        _progressStream.add(progress);
      } catch (e) { }
    });

    if (_recordDataMap.keys.contains(id)) {
      final data = _recordDataMap[id];

      try {
        _currentDuration = await _player?.startPlayer(fromDataBuffer: data, whenFinished: () {
          _delegate?.finishCallBack?.call();
          end();
        });
        _currentPlayingId = id;
      } catch (e) {
        _delegate?.msgCallBack?.call(e.toString());
      }
    } else if (_recordMap.keys.contains(id)) {
      final url = _recordMap[id] ?? "";
      try {
        _currentDuration = await _player?.startPlayer(fromURI: url, whenFinished: () {
          _delegate?.finishCallBack?.call();
          end();
        });
        _currentPlayingId = id;
      } catch (e) {
        _delegate?.msgCallBack?.call(e.toString());
      }
    }

  }

  Future<void> setPlayProgress(double progress) async {
    if (_currentPlayingId == null) {
      return;
    }
    final dureMi = (_currentDuration?.inMicroseconds?.toDouble() ?? 0.0) * progress;
    _player?.seekToPlayer(Duration(microseconds: dureMi.toInt()));
  }

  Future<void> _finish() async {

    await _player?.stopPlayer();
    if (_disposition != null) {
      _disposition?.cancel();
      _disposition = null;
      _player?.dispositionStream();
    }

    await _player?.closePlayer();
    _player = null;
    _currentDuration = null;
    _progress = 0.0;
    try {
      _progressStream.add(0.0);
    } catch (e) { }
    _delegate?.msgCallBack?.call("结束播放");
    _delegate = null;
    _currentPlayingId = null;
  }

}